package club.samubird.simpledatahandlekit.file.core;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.google.common.collect.Lists;
import com.sun.istack.internal.NotNull;
import javafx.util.Pair;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sam
 * @date 2019/10/9 14:11
 * @description 功能描述
 */
@Slf4j
public class SimpleEasyExcelUtil {

	private static List simpleReadOnlyOneSheet(String filePath, int readSheet, Boolean needHead) {
		SimpleReadContent simpleReadContent = new SimpleReadContent(needHead);
		ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder().file(filePath).autoCloseStream(true).autoTrim(true).ignoreEmptyRow(true).customObject(simpleReadContent);
		ExcelReaderSheetBuilder excelReaderSheetBuilder = excelReaderBuilder.sheet(readSheet).registerReadListener(new ReadListener() {

			@Override
			public void onException(Exception exception, AnalysisContext context) throws Exception {
				String filePath = context.readWorkbookHolder().getFile().getPath();
				log.info("在读取文件: {} 时出现异常: {} ", filePath, exception);
				throw exception;
			}

			@Override
			public void invoke(Object data, AnalysisContext context) {
				Map<Integer, Object> readMap = (Map<Integer, Object>) data;
				SimpleReadContent custom = (SimpleReadContent) context.getCustom();
				List contentList = custom.getContentList();
				Map<String, Object> resultMap = new HashMap<>(custom.maxLength);
				custom.getHeadMap().forEach(
						(k, v) -> resultMap.put(v, readMap.getOrDefault(k, null))
				);
				if (custom.needHead) {
					contentList.add(resultMap);
				} else {
					contentList.add(resultMap.values());
				}
			}

			@Override
			public void doAfterAllAnalysed(AnalysisContext context) {

			}

			@Override
			public boolean hasNext(AnalysisContext context) {
				return true;
			}

			@Override
			public void invokeHead(Map headMap, AnalysisContext context) {
				SimpleReadContent custom = (SimpleReadContent) context.getCustom();
				Map<Integer, String> head = (Map<Integer, String>) headMap.entrySet().stream().collect(Collectors.toMap(entry -> (Integer) ((Map.Entry) entry).getKey(), entry -> ((CellData) ((Map.Entry) entry).getValue()).getStringValue()));
				custom.setHeadMap(head);
				custom.maxLength = headMap.size();
			}
		});
		excelReaderSheetBuilder.doRead();
		return simpleReadContent.getContentList();
	}

	public static List<Map<String, Object>> simpleReadFirstSheetWithHead(String filePath) {
		return simpleReadOnlyOneSheet(filePath, 0, true);
	}

	public static List<List<Object>> simpleReadFirstSheetWithoutHead(String filePath) {
		return simpleReadOnlyOneSheet(filePath, 0, false);
	}

	public static void simpleWriteOneSheetWithoutHead(String filePath, @NotNull List<List> data) {
		// 删除已经存在的路径
		prepareFilePath(filePath);
		// 直接写文件
		EasyExcel.write(filePath).sheet("sheet1").doWrite(data);
	}

	private static void prepareFilePath(String filePath) {
		File file = new File(filePath);
		if (file.exists()) {
			file.delete();
			return;
		}
		File parentDir = new File(file.getParent());
		if (!parentDir.exists()) {
			parentDir.mkdirs();
		}
	}

	public static void simpleWriteOneSheetWithHead(String filePath, @NotNull List<Map> mapDataList) {
		// 删除已经存在的路径
		prepareFilePath(filePath);
		// 构建文件写对象
		ExcelWriter excelWriter = EasyExcel.write(filePath).build();
		// 构建表头和内容对
		Pair<List<List<String>>, List<List>> headContentPair = prepareHeadAndContent(mapDataList);
		// 构建Sheet写对象
		WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").head(headContentPair.getKey()).build();
		// 写数据
		excelWriter.write(headContentPair.getValue(), writeSheet);
		// 千万别忘记finish 会帮忙关闭流
		excelWriter.finish();
	}

	private static Pair<List<List<String>>, List<List>> prepareHeadAndContent(List<Map> mapDataList) {
		// 构建表头
		Optional<Map> maxMapOptional = mapDataList.parallelStream().max(Comparator.comparingInt(map -> map.values().size()));
		Map maxMap = maxMapOptional.orElse(mapDataList.get(0));
		List<String> headList = Lists.newArrayList();
		headList.addAll((List<String>) maxMap.keySet().stream().sorted().collect(Collectors.toList()));
		List head = headList.stream().map(Arrays::asList).collect(Collectors.toList());
		// 构建内容
		List<List> content = mapDataList.parallelStream().map(
				mapData -> headList.stream().map(k -> mapData.getOrDefault(k, "")).collect(Collectors.toList())
		).collect(Collectors.toList());
		return new Pair(head, content);
	}

	public static void simpleWriteSameSheetRepeatWithoutHead(String filePath, RepeatWriter<List<List>> repeatWriter) {
		// 删除已经存在的路径
		prepareFilePath(filePath);
		// 构建文件写对象
		ExcelWriter excelWriter = EasyExcel.write(filePath).build();
		// 构建sheet写对象
		WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build();
		while (repeatWriter.hasNextBatch()) {
			List<List> firstData = repeatWriter.first();
			excelWriter.write(firstData, writeSheet);
			List<List> nextData = repeatWriter.next();
			while (!CollectionUtils.isEmpty(nextData)) {
				excelWriter.write(nextData, writeSheet);
				nextData = repeatWriter.next();
			}
		}
		excelWriter.finish();
	}

	public static void simpleWriteDifferentSheetRepeatWithHead(String filePath, RepeatWriter<List<Map>> repeatWriter) {
		// 删除已经存在的路径
		prepareFilePath(filePath);
		// 构建文件写对象
		ExcelWriter excelWriter = EasyExcel.write(filePath).build();
		int sheetIndex = 0;
		while (repeatWriter.hasNextBatch()) {
			sheetIndex++;

			List<Map> firstMapList = repeatWriter.first();
			// 构建表头和内容对
			Pair<List<List<String>>, List<List>> headContentFirstPair = prepareHeadAndContent(firstMapList);
			// 构建Sheet写对象
			WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex - 1, "sheet" + sheetIndex).head(headContentFirstPair.getKey()).build();
			// 写数据
			excelWriter.write(headContentFirstPair.getValue(), writeSheet);

			List<Map> nextMapList = repeatWriter.next();
			while (!CollectionUtils.isEmpty(nextMapList)) {
				Pair<List<List<String>>, List<List>> headContentNextPair = prepareHeadAndContent(nextMapList);
				excelWriter.write(headContentNextPair.getValue(), writeSheet);
				nextMapList = repeatWriter.next();
			}
		}
		excelWriter.finish();
	}

}


@Data
class SimpleReadContent {
	Map<Integer, String> headMap;
	Boolean needHead;
	List contentList;
	int maxLength;

	SimpleReadContent(Boolean needHead) {
		this.needHead = Objects.nonNull(needHead) && needHead;
		if (this.needHead) {
			contentList = new LinkedList<Map<String, Object>>();
		} else {
			contentList = new LinkedList<List<Object>>();
		}
	}
}
